package com.ilia.rubik;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

public class HashCodeUtils {
    public static int getHashCodeForArray(int[] ints) {
        return computeHashCodeForArray(ints);
    }
    
    public static int computeHashCodeForArray(int[] ints) {
        int hash = 0;
        
        for (int i = 0; i < ints.length; i++) {
                hash += ints[i];
                hash += (hash<<10);
                hash ^= (hash>>6);
        }
        hash += (hash << 3);
        hash ^= (hash >> 11);
        hash += (hash << 15);
        
        return hash;
    }
    
    
    
    public static  int getHashCodeForCollection(Collection collection) {
        int[] ah = new int[collection.size()];
        int p = 0;
        for (Iterator iter = collection.iterator(); iter.hasNext();) {
          Object value = iter.next();
          ah[p] = value.hashCode();
          p++;
        }
        int hc = HashCodeUtils.computeHashCodeForArray(ah);
        return hc;
    }
    
    public static int getHashCodeForObjectArray(Object[] array) {
        if (array==null) return 0;
        int[] arr = new int[array.length];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = array[i].hashCode();
        }
        return computeHashCodeForArray(arr);
    }
    
    public static boolean equalsObjects(Object obj1, Object obj2) {
        if ((obj1 instanceof Object[]) && (obj2 instanceof Object[])) {
            return equalsArrays((Object[]) obj1, (Object[]) obj2);
        } else {
            return obj1.equals(obj2);
        }
    }
    
    public static boolean equalsArrays(Object[] obj1, Object[] obj2) {
        if ((obj1==null)||(obj2==null)) return false;
        if (obj1.length!=obj2.length) return false;
        for (int i = 0; i < obj2.length; i++) {
            if (!equalsObjects(obj1[i],obj2[i])) return false;
        }
        return true;
    }
    
    public static int getHashCodeForMap(Map map) {
        int[] props = new int[map.keySet().size()*2];
        int p = 0;
        for (Iterator iter = map.keySet().iterator(); iter.hasNext();) {
            Object key = iter.next();
            Object value = map.get(key);
            props[2*p] = key.hashCode();
            props[2*p + 1] = getHashCodeForValue(value);
            p++;
        }
        int hc = HashCodeUtils.computeHashCodeForArray(props);
        return hc;
    }
    
    public static  int getHashCodeForValue(Object value) {
        if (value==null) return 0;
        if (value.getClass().isArray()) {
            Object[] arr = (Object[])value;
            int[] ah = new int[arr.length];
            for (int i = 0; i < ah.length; i++) {
                if (arr[i]!=null) {
                    ah[i] = arr[i].hashCode();
                } else {
                    ah[i] = i;
                }
            }
            int hc = HashCodeUtils.computeHashCodeForArray(ah);
            return hc;
        } else if (value instanceof Map) {
            return getHashCodeForMap((Map)value);
        } else if (value instanceof Collection) {
            return getHashCodeForCollection((Collection)value);
        } else {
            return value.hashCode();
        }
    }    
}
